package com.gwaeron.game;

// JFC
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

// GTGE
import com.golden.gamedev.object.sprite.AdvanceSprite;

public class RPGSprite extends AdvanceSprite {

	// sprite constant direction
	public static final int LEFT = 0;
	public static final int RIGHT = 1;
	public static final int UP = 2;
	public static final int DOWN = 3;

	// sprite constant status
	public static final int STANDING = 0, MOVING = 1;

	public static final int[][] movingAnimation = new int[][] {
			{ 10, 11, 10, 9 }, // left animation
			{ 4, 5, 4, 3 }, // right animation
			{ 1, 2, 1, 0 }, // up animation
			{ 7, 8, 7, 6 } }; // down animation

	int tileX, tileY;
	public boolean running;
	RPGGame owner;
	Map map;
	double speed;
	int nextFrame;
	int verticalMovement;
	int[][] level;

	public RPGSprite(RPGGame owner, BufferedImage[] images, int tileX,
			int tileY, int moveSpeed, int direction) {
		super(images, (tileX * 32) - 8, (tileY * 32) - 32);
		this.owner = owner;
		this.map = owner.map;
		this.level = map.getLevels();
		this.tileX = tileX;
		this.tileY = tileY;
		this.running = false;
		this.verticalMovement = 8;
		map.layer3[tileX][tileY] = this; // mark sprite position

		// init status, standing facing direction
		setAnimation(STANDING, direction);

		// the animation speed related with movement speed
		getAnimationTimer().setDelay(2 * 550 / moveSpeed);

		speed = 0.04 * moveSpeed;
		this.nextFrame = 1;
	}

	public void updateElevation() {
		this.level = map.getLevels();
	}

	public void update(long elapsedTime) {
		super.update(elapsedTime);

		if (getStatus() == MOVING) {
			if (moveTo(elapsedTime, (tileX * 32) - 8, (tileY * 32) - 32
					- level[tileX][tileY], speed)) {
				setStatus(STANDING);
				// next frame
				setFrame(0); // This sets it to "movement" frame. TODO: This is
								// a very temporary solution, if one takes one
								// step at a time, every second step will be
								// without an animation.
				nextFrame = (nextFrame + 1) % 4;
			}
		}

		if (getStatus() == STANDING) {
			// update next sprite logic

			updateLogic(elapsedTime);
		}

	}

	// the npc is standing and do nothing, time to think what to do next
	protected void updateLogic(long elapsedTime) {
	}

	// sprite is walking to tileX+horiz, tileY+vert
	boolean walkTo(int dir, int horiz, int vert) {
		setDirection(dir);

		if (map.isOccupied(tileX + horiz, tileY + vert) == true) {
			// tile is not empty!
			// can't go to this direction
			return false;
		}

		// unoccupy old location
		map.layer3[tileX][tileY] = null;

		// set new location
		tileX += horiz;
		tileY += vert;
		// occupy new location
		map.layer3[tileX][tileY] = this; // This causes some trouble with
											// foreground sprites, i.e., it sets
											// the new location while it's still
											// moving, so if moving vertically
											// it will be "ahead" of some
											// foreground sprites (move
											// downwards, while still covered by
											// some building will still give the
											// position of the char, while
											// overlapping, as in front of the
											// specific foreground tile, meaning
											// it will show the character's head
											// while moving). A temporary
											// solution now in place is that
											// foreground sprites always have
											// higher priority (comparator
											// value) than other sprites, but
											// this also means it's impossible
											// to ever go in front of any such
											// tiles.

		setStatus(MOVING);

		// next frame
		setFrame(nextFrame); // This sets to the "static" frame. TODO: See
								// update(), same thing.

		return true;
	}

	protected void animationChanged(int oldStat, int oldDir, int status,
			int direction) {
		setAnimationFrame(movingAnimation[direction]);
	}

	public void render(Graphics2D g) {
		// sometime the sprite/npc/event has no image
		if (getImages() != null) {
			super.render(g);
		}
	}

	public void toggleRun(boolean running) {
		this.running = running;
		if (running)
			this.speed = 0.04 * 10;
		else
			this.speed = 0.04 * 4;
	}

	public boolean isRunning() {
		return this.running;
	}

}